<template>
	<view class="container">
		<!-- 顶部结果展示区域 -->
		<view class="result-container">
			<view class="result-header">
				<text class="result-title">语音转文字</text>
				<text class="result-time">{{ lastConvertTime }}</text>
			</view>
			<scroll-view scroll-y class="result-content">
				<text class="result-text">{{ transcription }}</text>
			</scroll-view>
		</view>
		<!-- 声音动画效果区域 -->
		<view class="wave-container" v-show="isRecording">
			<view v-for="(bar, index) in waveBars" :key="index" class="wave-bar" :style="{ height: `${bar.height}px`, backgroundColor: bar.color }"></view>
		</view>
		<!-- 录音按钮 -->
		<!-- @touchstart="startTest" @touchend="stopTest" -->
		<view class="record-button" :class="{ active: isRecording }" @mousedown="startTest" @mouseup="stopTest">
			<view class="button-inner">
				<text v-if="!isRecording">按住说话</text>
				<text v-else>松开结束</text>
			</view>
		</view>
		<!-- 状态提示 -->
		<view class="status-message">
			<text>{{ statusMessage }}</text>
		</view>
		<!-- 权限提示 -->
		<view v-if="showPermissionWarning" class="permission-warning">
			<text>请允许麦克风权限以使用语音功能</text>
		</view>
	</view>
</template>

<script>
import createIatRecorder from 'kdxf-web';
import CryptoJS from 'crypto-js';
// 科大讯飞API配置（根据文档要求）
const XUNFEI_CONFIG = {
	APP_ID: '1d450eb0',
	API_KEY: '6b60bf4485792b32cc012636bfd8efc8',
	API_SECRET: 'MjA3ZTNiMTIzZjE3ZDJkNGNkOTRkNTli',
	HOST: 'iat-api.xfyun.cn',
	PATH: '/v2/iat'
};

const config = {
	hostUrl: 'wss://iat-api.xfyun.cn/v2/iat',
	host: 'iat-api.xfyun.cn',
	appid: '1d450eb0', // 填写您的科大讯飞应用ID
	apiSecret: 'MjA3ZTNiMTIzZjE3ZDJkNGNkOTRkNTli', // 填写您的科大讯飞API密钥
	apiKey: '6b60bf4485792b32cc012636bfd8efc8', // 填写您的科大讯飞API密钥
	uri: '/v2/iat'
};

export default {
	data() {
		return {
			isRecording: false,
			transcription: '',
			statusMessage: '准备就绪',
			lastConvertTime: '',
			showPermissionWarning: false,
			waveBars: Array(8)
				.fill()
				.map(() => ({ height: 20, color: '#4a9ff5' })),
			audioContext: null,
			audioSource: null,
			scriptProcessor: null,
			xunfeiSocket: null,
			timer: null,
			recordingStartTime: 0,
			audioBuffer: [],
			audioBufferSize: 0,
			iatRecorder: null
		};
	},
	mounted() {
		// this.checkMicrophonePermission();
	},
	methods: {
		initIatRecorder() {
			this.iatRecorder = createIatRecorder(config);
			// 设置文本变化回调
			this.iatRecorder.onTextChange = (text) => {
				console.log('当前识别文本:', text);
			};
			// 设置识别完成回调
			this.iatRecorder.onRecognitionComplete = (text) => {
				console.log('识别完成:', text);
			};
			// 设置状态变化回调
			this.iatRecorder.onWillStatusChange = (oldStatus, newStatus) => {
				console.log(`状态从 ${oldStatus} 变为 ${newStatus}`);
			};
		},
		startTest() {
			console.log('startTest');
			if (!this.iatRecorder) {
				this.initIatRecorder();
			} else {
				this.iatRecorder.start();
			}
		},
		stopTest() {
			console.log('stopTest');
			this.iatRecorder.stop();
		},
		// 检查麦克风权限
		async checkMicrophonePermission() {
			try {
				const permission = await navigator.permissions.query({ name: 'microphone' });
				this.showPermissionWarning = permission.state !== 'granted';

				permission.onchange = () => {
					this.showPermissionWarning = permission.state !== 'granted';
				};
			} catch (error) {
				console.error('权限检查失败:', error);
			}
		},

		// 开始录音（使用AudioContext直接获取PCM数据）
		async startRecording() {
			if (this.isRecording) return;

			try {
				// 重置状态
				this.isRecording = true;
				this.statusMessage = '录音中...';
				this.transcription = '';
				this.lastConvertTime = '';
				this.recordingStartTime = Date.now();
				this.audioBuffer = [];
				this.audioBufferSize = 0;

				// 获取麦克风权限
				const stream = await navigator.mediaDevices.getUserMedia({
					audio: {
						sampleRate: 16000,
						channelCount: 1,
						echoCancellation: true
					}
				});

				// 创建音频上下文
				this.audioContext = new (window.AudioContext || window.webkitAudioContext)({
					sampleRate: 16000
				});

				// 创建音频源
				this.audioSource = this.audioContext.createMediaStreamSource(stream);

				// 创建脚本处理器（直接获取PCM数据）
				this.scriptProcessor = this.audioContext.createScriptProcessor(1024, 1, 1);

				// 处理音频数据
				this.scriptProcessor.onaudioprocess = (event) => {
					if (!this.isRecording) return;

					// 获取PCM数据（Float32Array）
					const inputData = event.inputBuffer.getChannelData(0);

					// 转换为16位PCM（Int16Array）
					const pcmData = this.float32ToInt16(inputData);

					// 添加到缓冲区
					this.audioBuffer.push(pcmData);
					this.audioBufferSize += pcmData.length;

					// 每640个采样点（1280字节）发送一次（40ms音频）
					if (this.audioBufferSize >= 640) {
						this.sendAudioData();
					}
				};

				// 连接节点
				this.audioSource.connect(this.scriptProcessor);
				this.scriptProcessor.connect(this.audioContext.destination);

				// 启动声波动画
				this.startWaveAnimation();

				// 连接科大讯飞服务
				await this.connectXunfei();
			} catch (error) {
				console.error('录音启动失败:', error);
				this.statusMessage = '无法访问麦克风';
				this.isRecording = false;
				this.showPermissionWarning = true;
			}
		},

		// 停止录音
		stopRecording() {
			if (!this.isRecording) return;

			clearInterval(this.timer);
			this.isRecording = false;
			this.statusMessage = '正在转换语音...';

			// 发送剩余音频数据
			if (this.audioBuffer.length > 0) {
				this.sendAudioData();
			}

			// 发送结束帧
			this.sendEndFrame();

			// 断开音频节点
			if (this.audioSource) {
				this.audioSource.disconnect();
			}
			if (this.scriptProcessor) {
				this.scriptProcessor.disconnect();
			}
			if (this.audioContext) {
				this.audioContext.close();
			}

			// 关闭WebSocket连接
			if (this.xunfeiSocket) {
				try {
					this.xunfeiSocket.close();
				} catch (e) {
					console.warn('关闭WebSocket时出错', e);
				}
				this.xunfeiSocket = null;
			}

			// 记录转换时间
			this.lastConvertTime = this.formatTime(new Date());
		},

		// 启动声波动画
		startWaveAnimation() {
			clearInterval(this.timer);

			this.timer = setInterval(() => {
				this.waveBars = this.waveBars.map((bar) => {
					const randomHeight = 20 + Math.floor(Math.random() * 80);
					const randomColor = `hsl(${200 + Math.random() * 60}, 80%, 60%)`;
					return {
						height: this.isRecording ? randomHeight : 20,
						color: randomColor
					};
				});
			}, 200);
		},

		// 连接科大讯飞服务
		async connectXunfei() {
			return new Promise((resolve, reject) => {
				try {
					// 生成鉴权URL
					const authUrl = this.generateAuthUrl();

					this.xunfeiSocket = new WebSocket(authUrl);

					this.xunfeiSocket.onopen = () => {
						this.statusMessage = '已连接语音识别服务';

						// 发送初始化数据（根据文档要求）
						const initData = {
							common: {
								app_id: XUNFEI_CONFIG.APP_ID
							},
							business: {
								language: 'zh_cn',
								domain: 'iat',
								accent: 'mandarin',
								vad_eos: 2000,
								dwa: 'wpgs' // 开启动态修正
							},
							data: {
								status: 0, // 第一帧
								format: 'audio/L16;rate=16000',
								encoding: 'raw'
							}
						};

						this.xunfeiSocket.send(JSON.stringify(initData));
						resolve();
					};

					this.xunfeiSocket.onmessage = (event) => {
						const result = JSON.parse(event.data);
						this.processXunfeiResponse(result);
					};

					this.xunfeiSocket.onerror = (error) => {
						console.error('科大讯飞连接错误:', error);
						this.statusMessage = '语音识别服务连接失败';
						reject(error);
					};

					this.xunfeiSocket.onclose = () => {
						if (this.isRecording) {
							this.statusMessage = '语音识别连接意外断开';
						} else {
							this.statusMessage = '语音识别服务已断开';
						}
					};
				} catch (error) {
					console.error('连接科大讯飞失败:', error);
					this.statusMessage = '无法连接语音识别服务';
					reject(error);
				}
			});
		},

		// 生成鉴权URL（根据文档要求）
		generateAuthUrl() {
			const date = new Date().toGMTString();
			const signatureOrigin = `host: ${XUNFEI_CONFIG.HOST}\ndate: ${date}\nGET ${XUNFEI_CONFIG.PATH} HTTP/1.1`;

			// 使用CryptoJS进行HMAC-SHA256加密
			const signatureSha = CryptoJS.HmacSHA256(signatureOrigin, XUNFEI_CONFIG.API_SECRET);
			const signature = CryptoJS.enc.Base64.stringify(signatureSha);

			const authorizationOrigin = `api_key="${XUNFEI_CONFIG.API_KEY}", algorithm="hmac-sha256", headers="host date request-line", signature="${signature}"`;
			const authorization = btoa(authorizationOrigin);

			return `wss://${XUNFEI_CONFIG.HOST}${XUNFEI_CONFIG.PATH}?authorization=${authorization}&date=${encodeURIComponent(date)}&host=${XUNFEI_CONFIG.HOST}`;
		},

		// 处理科大讯飞响应（支持动态修正）
		processXunfeiResponse(response) {
			if (response.code !== 0) {
				console.error('科大讯飞错误:', response);
				this.statusMessage = `语音识别错误: ${response.message || `代码${response.code}`}`;
				return;
			}

			// 处理动态修正结果
			if (response.data && response.data.result) {
				const result = response.data.result;

				// 最终结果（status=2）
				if (response.data.status === 2) {
					this.transcription = result.ws.map((ws) => ws.cw.map((cw) => cw.w).join('')).join('');
				}
				// 中间结果（status=1）
				else if (response.data.status === 1) {
					// 使用wpgs服务时的中间结果处理
					if (result.pgs === 'rpl') {
						// 替换之前的结果
						const newText = result.rg.map((idx) => result.ws[idx].cw.map((cw) => cw.w).join('')).join('');

						this.transcription = newText;
					} else {
						// 追加新结果
						const newText = result.ws.map((ws) => ws.cw.map((cw) => cw.w).join('')).join('');

						this.transcription += newText;
					}
				}
			}
		},

		// 发送音频数据（符合文档要求的格式）
		sendAudioData() {
			if (!this.xunfeiSocket || this.xunfeiSocket.readyState !== WebSocket.OPEN) {
				return;
			}
			try {
				// 合并缓冲区数据
				const totalLength = this.audioBuffer.reduce((sum, arr) => sum + arr.length, 0);
				const mergedData = new Int16Array(totalLength);
				let offset = 0;
				this.audioBuffer.forEach((arr) => {
					mergedData.set(arr, offset);
					offset += arr.length;
				});
				// 发送二进制音频数据
				this.xunfeiSocket.send(mergedData.buffer);
				// 重置缓冲区
				this.audioBuffer = [];
				this.audioBufferSize = 0;
			} catch (error) {
				console.error('发送音频数据失败:', error);
			}
		},
		// 发送结束帧（根据文档要求）
		sendEndFrame() {
			if (!this.xunfeiSocket || this.xunfeiSocket.readyState !== WebSocket.OPEN) {
				return;
			}
			try {
				const endData = JSON.stringify({
					data: {
						status: 2, // 结束帧
						format: 'audio/L16;rate=16000',
						encoding: 'raw'
					}
				});
				this.xunfeiSocket.send(endData);
			} catch (error) {
				console.error('发送结束帧失败:', error);
			}
		},
		// 将Float32转换为Int16（符合PCM格式要求）
		float32ToInt16(buffer) {
			const length = buffer.length;
			const result = new Int16Array(length);
			for (let i = 0; i < length; i++) {
				// 将-1.0到1.0的浮点数转换为-32768到32767的整数
				const sample = buffer[i] * 0x7fff;
				result[i] = sample < 0 ? Math.max(sample, -0x8000) : Math.min(sample, 0x7fff);
			}
			return result;
		},
		// 格式化时间
		formatTime(date) {
			const hours = date.getHours().toString().padStart(2, '0');
			const minutes = date.getMinutes().toString().padStart(2, '0');
			return `${hours}:${minutes}`;
		}
	}
};
</script>

<style lang="scss" scoped>
@import 'xunfei.scss';
</style>
